﻿#include "stdafx.h"
#include "DbTool.h"
#include <boost/format.hpp>
#include "DefInfo/GameInfo.h"
#include <atlconv.h>
#include "Routine/Common/RoutineConfig.h"

DbTool::DbTool() {
}

void DbTool::CheckTable() {
	if (!IsTableExist("SpellDef")) {
		CreateTable_SpellDef();
		WriteCurrentSpellConfigToDB();
	}
}

bool DbTool::IsTableExist(std::string table_name) {
	std::string sql;
	sql = str(boost::format("select name from sqlite_master where name='%s';") % table_name.c_str());
	rc_ = sqlite3_get_table(db_, sql.c_str(), &results_, &nrows_, &ncols_, &errmsg_);
	if (rc_ != SQLITE_OK) {
		throw std::exception("sql error");
	}
	else {
		if (nrows_ == 0) {
			return false;
		}
	}
	sqlite3_free_table(results_);
	return true;
}

void DbTool::CreateTable_SpellDef() {
	const char * createTableSQL = "CREATE TABLE 'SpellDef' ('spell_id'  INTEGER NOT NULL,'gcd'  INTEGER NOT NULL,'spell_name_en'  TEXT NOT NULL,'spell_name_cn'  TEXT NOT NULL,PRIMARY KEY ('spell_id' ASC));";
	sqlite3_stmt * stmt = NULL;
	int len = (int)strlen(createTableSQL);
	if (sqlite3_prepare_v2(db_, createTableSQL, len, &stmt, NULL) != SQLITE_OK) {
		throw std::exception("sql error");
	}
	if (sqlite3_step(stmt) != SQLITE_DONE) {
		throw std::exception("sql error");
	}
	sqlite3_finalize(stmt);
}

void DbTool::WriteCurrentSpellConfigToDB() {
	sqlite3_exec(db_, "begin;", 0, 0, 0);
	std::string sql;
	sql = "INSERT INTO 'main'.'SpellDef' VALUES (?, ?, ?, ?);";
	sqlite3_stmt * stmt = NULL;
	if (sqlite3_prepare_v2(db_, sql.c_str(), (int)sql.length(), &stmt, NULL) != SQLITE_OK) {
		throw std::exception("sql error");
	}
	for (auto & pair : GameInfo::inst().map_spell_config_) {
		SpellConfig & sc = pair.second;
		if (sc.name_cn != "" && sc.spell_id > 0) {
			InsertSpellConfigToTable(sc, stmt);
		}
	}
	sqlite3_finalize(stmt);
	sqlite3_exec(db_, "commit;", 0, 0, 0);
}


//GB2312到UTF-8的转换
static int GB2312ToUtf8(const char * gb2312, char * utf8) {
	int len = MultiByteToWideChar(CP_ACP, 0, gb2312, -1, NULL, 0);
	wchar_t * wstr = new wchar_t[len + 1];
	memset(wstr, 0, len + 1);
	MultiByteToWideChar(CP_ACP, 0, gb2312, -1, wstr, len);
	len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
	WideCharToMultiByte(CP_UTF8, 0, wstr, -1, utf8, len, NULL, NULL);
	if (wstr) {
		delete[] wstr;
	}
	return len;
}

//UTF-8到GB2312的转换
static int Utf8ToGB2312(const char * utf8, char * gb2312) {
	int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
	wchar_t * wstr = new wchar_t[len + 1];
	memset(wstr, 0, len + 1);
	MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wstr, len);
	len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
	WideCharToMultiByte(CP_ACP, 0, wstr, -1, gb2312, len, NULL, NULL);
	if (wstr) {
		delete[] wstr;
	}
	return len;
}

void DbTool::InsertSpellConfigToTable(SpellConfig & sc, sqlite3_stmt * stmt) {
	sqlite3_reset(stmt);
	sqlite3_bind_int(stmt, 1, sc.spell_id);
	CT2A name(sc.name_cn);
	char buff_u8[128];
	GB2312ToUtf8(name.m_psz, buff_u8);
	sqlite3_bind_int(stmt, 2, sc.need_gcd);
	sqlite3_bind_text(stmt, 3, "", (int)0, SQLITE_STATIC);
	sqlite3_bind_text(stmt, 4, buff_u8, (int)strlen(buff_u8), SQLITE_STATIC);
	if (sqlite3_step(stmt) != SQLITE_DONE) {
		throw std::exception("sql error");
	}
}

DbTool & DbTool::inst() {
	static DbTool inst;
	return inst;
}

DbTool::~DbTool() {
	CloseDB();
}

bool DbTool::ConnectDB() {
	int rc;
	rc = sqlite3_open("./demo.db", &db_);
	if (rc) {
		fprintf(stderr, "can't open db! [%s]\n", sqlite3_errmsg(db_));
		sqlite3_close(db_);
		exit(1);
	}
	else {
		printf("db open successfully!\n");
	}
	CheckTable();
	return true;
}

bool DbTool::CloseDB() {
	if (db_ != NULL) {
		sqlite3_close(db_);
	}
	return true;
}

bool DbTool::InsertEmptySpellConfig(SpellConfig & sc) {
	std::string sql;
	sqlite3_stmt * stmt = NULL;
	sql = str(boost::format("INSERT INTO 'main'.'SpellDef' VALUES(%d, %d, '%s', '%s');")
		% sc.spell_id % 1 % "" % "");
	if (sqlite3_prepare_v2(db_, sql.c_str(), (int)sql.length(), &stmt, NULL) != SQLITE_OK) {
		throw std::exception("sql error");
	}
	if (sqlite3_step(stmt) != SQLITE_DONE) {
		throw std::exception("sql error");
	}
	sqlite3_finalize(stmt);
	return true;
}

bool DbTool::UpdateProperty(Property& prop)
{
	std::string sql;
	sqlite3_stmt * stmt = NULL;
	std::string name_utf8;
	name_utf8.resize(127, ' ');
	GB2312ToUtf8(prop.name.c_str(), &name_utf8[0]);
	sql = str(boost::format("SELECT property.name, property.value_int, property.value_f, \
property.condition_cat FROM property WHERE property.name='%s' and property.spec_id=%d")
% name_utf8.c_str() % prop.spec_id);
	rc_ = sqlite3_get_table(db_, sql.c_str(), &results_, &nrows_, &ncols_, &errmsg_);
	if (rc_ != SQLITE_OK) {
		throw std::exception("sql error");
	}
	if (nrows_ > 0)
	{
		// 更新数据
		sql = str(boost::format("UPDATE 'main'.'property' SET [value_int] = %d \
,[value_f] = %0.4f, [condition_cat]= %d WHERE [name] = '%s' and [spec_id]=%d")
% std::any_cast<int>(prop.value2) % std::any_cast<double>(prop.value)
% (int)prop.condition % name_utf8.c_str() % prop.spec_id);
		if (sqlite3_prepare_v2(db_, sql.c_str(), (int)sql.length(), &stmt, NULL) != SQLITE_OK) {
			throw std::exception("sql error");
		}
		if (sqlite3_step(stmt) != SQLITE_DONE) {
			throw std::exception("sql error");
		}
	}
	else
	{
		sql = str(boost::format("INSERT INTO 'main'.'property'([name], [value_f], [value_int],\
 [condition_cat], [spec_id]) VALUES('%s' , %.2f, %d, %d, %d)")
			% name_utf8.c_str() % std::any_cast<double>(prop.value)
			% std::any_cast<int>(prop.value2) % (int)prop.condition % prop.spec_id);
		if (sqlite3_prepare_v2(db_, sql.c_str(), (int)sql.length(), &stmt, NULL) != SQLITE_OK) {
			throw std::exception("sql error");
		}
		if (sqlite3_step(stmt) != SQLITE_DONE) {
			throw std::exception("sql error");
		}
	}
	sqlite3_finalize(stmt);
	sqlite3_free_table(results_);
	return true;
}

bool DbTool::LoadAllSpellDef() {
	std::string sql;
	sql = str(boost::format("SELECT SpellDef.spell_id, SpellDef.gcd, SpellDef.spell_name_en, SpellDef.spell_name_cn FROM SpellDef "));
	rc_ = sqlite3_get_table(db_, sql.c_str(), &results_, &nrows_, &ncols_, &errmsg_);
	if (rc_ != SQLITE_OK) {
		throw std::exception("sql error");
	}
	else {
		vec_spell_config_.clear();
		int nIndex = 0;
		for (int i = 0; i <= nrows_; i++) {
			if (i > 0) {
				SpellConfigPtr ptr = std::make_shared<SpellConfig>();
				SpellConfig& sc = *ptr;
				sc.spell_id = atoi(results_[nIndex++]);
				sc.need_gcd = atoi(results_[nIndex++]);
				sc.name_en = results_[nIndex++];
				char buff_gb2312[128];
				Utf8ToGB2312(results_[nIndex++], buff_gb2312);
				CA2T name(buff_gb2312);
				sc.name_cn = name;
				if (ptr->name_en == L"")
				{
					ptr->name_en = "UnknowName";
				}
				if (ptr->name_cn == L"")
				{
					ptr->name_cn = "未知法术";
				}
				vec_spell_config_.push_back(ptr);
			}
			else {
				nIndex += ncols_;
			}
		}
	}
	sqlite3_free_table(results_);
	return true;
}

const DbTool::VecSpellConfig& DbTool::GetSpellConfig()
{
	return vec_spell_config_;
}

const DbTool::VecPropertyConfig& DbTool::GetPropertyConfig()
{
	return vec_property_config;
}

bool DbTool::LoadPropertyDef()
{
	std::string sql;
	sqlite3_stmt * stmt = NULL;
	sql = str(boost::format("SELECT property.name, property.value_f, property.value_int, property.condition_cat, property.spec_id FROM property"));
	rc_ = sqlite3_get_table(db_, sql.c_str(), &results_, &nrows_, &ncols_, &errmsg_);
	if (rc_ != SQLITE_OK) {
		throw std::exception("sql error");
	}
	else
	{
		vec_property_config.clear();
		int nIndex = 0;
		for (int i = 0; i <= nrows_; i++) {
			if (i > 0) {
				PropertyConfigPtr ptr = std::make_shared<Property>();
				Property& sc = *ptr;
				char buff_gb2312[128];
				Utf8ToGB2312(results_[nIndex++], buff_gb2312);
				sc.name = buff_gb2312;
				sc.value = atof(results_[nIndex++]);
				sc.value2 = atoi(results_[nIndex++]);
				sc.condition = (PropertyCondition)atoi(results_[nIndex++]);
				sc.spec_id = (SpecializationID)atoi(results_[nIndex++]);
				vec_property_config.push_back(ptr);
			}
			else {
				nIndex += ncols_;
			}
		}
	}
	sqlite3_free_table(results_);
	return true;
}

